<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    function useMutationObserver(callback) {
        let iterations = 0;
        const observer = new MutationObserver(callback);
        const node = document.createTextNode('');
        // characterData 设为 true 以监视指定目标节点或子节点树中节点所包含的字符数据的变化。
        observer.observe(node, {characterData: true});

        return function () {
            node.data = iterations = ++iterations % 2;
        };
    }

    // 异步操作“未完成”（pending）
    // 异步操作“已完成”（resolved，又称fulfilled）
    // 异步操作“失败”（rejected）
    //
    // 这三种的状态的变化途径只有两种。
    // 异步操作从“未完成”到“已完成”
    // 异步操作从“未完成”到“失败”。
    // 这种变化只能发生一次，一旦当前状态变为“已完成”或“失败”，就意味着不会再有新的状态变化了。因此，Promise对象的最终结果只有两种。
    //
    // 异步操作成功，Promise对象传回一个值，状态变为resolved。
    // 异步操作失败，Promise对象抛出一个错误，状态变为rejected。
    class SelfPromise {
        #promiseState = 'pending'
        #resolveCallback = null
        #rejectCallback = null
        #finallyCallback = null

        static isFunc(func) {
            return typeof func === 'function'
        }

        constructor(executor = (resolve, reject) => {
        }) {
            executor(successValue => {
                // 如果状态是 rejected，则 then 不执行
                if (this.#promiseState === 'rejected') return
                this.#promiseState = 'resolved'
                useMutationObserver(() => {
                    SelfPromise.isFunc(this.#resolveCallback) && this.#resolveCallback(successValue)
                    SelfPromise.isFunc(this.#finallyCallback) && this.#finallyCallback()
                })()
            }, errorValue => {
                // 如果状态是 resolved，则 catch 不执行
                if (this.#promiseState === 'resolved') return
                this.#promiseState = 'rejected'
                useMutationObserver(() => {
                    SelfPromise.isFunc(this.#rejectCallback) && this.#rejectCallback(errorValue)
                    SelfPromise.isFunc(this.#finallyCallback) && this.#finallyCallback()
                })()
            })
        }

        then(callback) {
            this.#resolveCallback = callback
            return this
        }

        catch(callback) {
            this.#rejectCallback = callback
            return this
        }

        finally(callback) {
            this.#finallyCallback = callback
            return this
        }
    }

console.log('start')

setTimeout(() => {
    console.log('setTimeout')
})

const p = new SelfPromise((resolve, reject) => {
    console.log('promise')
    reject('error')
}).then(res => {
    console.log(res, 'then');
}).catch(err => {
    console.error(err, 'catch');
}).finally(() => {
    console.log('finally')
})

console.log('end')
</script>
</body>
</html>
